﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;

using ERPStore.Monitor.Models;

namespace ERPStore.Monitor
{
	public class MonitorApplication : System.Windows.Forms.ApplicationContext
	{
		Views.IMonitorView m_View;
		Models.Settings m_Settings;

		public MonitorApplication()
		{
			m_View = new Views.MonitorView();
			m_View.StartConfiguration += StartConfiguration;
			m_View.ForceTask += ForceTask;
			this.MainForm = (System.Windows.Forms.Form)m_View;
		}

		protected Services.SettingsService SettingsService { get; private set; }
		protected List<Services.TasksListner> TasksListnerList { get; private set; }
		protected List<Services.LogListner> LogListnerList { get; private set; }

		public void Run()
		{
			SettingsService = new Services.SettingsService();

			m_Settings = SettingsService.GetSettings();

			if (m_Settings.MonitoredApplicationList.Count == 0)
			{
				StartConfiguration();
				if (m_Settings.MonitoredApplicationList.Count == 0)
				{
					return;
				}
				SettingsService.SaveSettings(m_Settings);
			}

			TasksListnerList = new List<Services.TasksListner>();
			LogListnerList = new List<Services.LogListner>();
			foreach (var item in m_Settings.MonitoredApplicationList)
			{
				if (!item.Enabled)
				{
					continue;
				}
				var tl = new Services.TasksListner(item);
				InitializeTaskListner(tl);
				TasksListnerList.Add(tl);

				var ll = new Services.LogListner(item);
				InitializeLogListner(ll);
				LogListnerList.Add(ll);
			}

			m_View.Show();

			System.Threading.Tasks.Task.Factory.StartNew(() =>
				{
					foreach (var item in TasksListnerList)
					{
						try
						{
							item.Start();
						}
						catch(Exception ex)
						{
							Error(ex);
						}
					}
					foreach (var item in LogListnerList)
					{
						try
						{
							item.Start();
						}
						catch(Exception ex)
						{
							Error(ex);
						}
					}
				});

			Application.Run(this);

			foreach (var item in TasksListnerList)
			{
				item.Stop();
			}
			foreach (var item in LogListnerList)
			{
				item.Stop();
			}
		}

		void InitializeTaskListner(Services.TasksListner taskListner)
		{
			taskListner.MessageReceived += (message) =>
			{
				m_View.AppendTaskMessage(message);
			};
			taskListner.ListChanged += () =>
			{
				m_View.RefreshTaskList();
			};
			taskListner.Error += Error;
			taskListner.AddTask += AddTask;
			taskListner.UpdateTask += UpdateTask;
			taskListner.TaskStarted += TaskStarted;
			taskListner.TaskTerminated += TaskTerminated;
		}

		void InitializeLogListner(Services.LogListner logListner)
		{
			logListner.AddLog = AddLog;
			logListner.Error += Error;
		}

		void StartConfiguration()
		{
			var configurationView = new Views.ConfigurationView(m_Settings);
			var result = configurationView.ShowDialog();

			if (result == System.Windows.Forms.DialogResult.OK)
			{
				SettingsService.SaveSettings(m_Settings);
			}
		}

		void ForceTask(ViewModels.TaskEntryViewModel task)
		{
			var tl = TasksListnerList.SingleOrDefault(i => i.ApiUrl == task.ApiUrl);
			if (tl != null)
			{
				tl.ForceTask(task.Name);
			}
		}

		void Error(Exception error)
		{
			m_View.Notify(error.ToString());
		}

		void AddLog(Models.Log log)
		{
			if (log.Category == Models.Category.Debug
					&& !m_Settings.LogDebugEnabled)
			{
				return;
			}

			m_View.AddLog(new ViewModels.LogViewModel(log));
		}

		void AddTask(ERPStore.Tasks.ViewModels.Task task, string apiUrl)
		{
			var vm = new ViewModels.TaskEntryViewModel(task);
			vm.ApiUrl = apiUrl;
			m_View.AddTask(vm);
		}

		void UpdateTask(ERPStore.Tasks.ViewModels.Task task, string apiUrl)
		{
			var exising = m_View.TaskList.SingleOrDefault(i => i.Name == task.Name 
				&& i.ApplicationName == task.ApplicationName 
				&& i.ApiUrl == apiUrl);

			if (exising != null)
			{
				var index = m_View.TaskList.IndexOf(exising);
				var vm = new ViewModels.TaskEntryViewModel(task);
				vm.ApiUrl = apiUrl;
				m_View.TaskList[index] = vm;
			}
			else
			{
				AddTask(task, apiUrl);
			}
		}

		void TaskStarted(string taskName, string machineName, string hostName)
		{
			var existing = m_View.TaskList.SingleOrDefault(i => i.Name == taskName
				&& i.MachineName == machineName
				&& i.HostName == hostName);
			if (existing != null)
			{
				existing.IsRunning = true;
			}
		}

		void TaskTerminated(string taskName, string machineName, string hostName)
		{
			var existing = m_View.TaskList.SingleOrDefault(i => i.Name == taskName
				&& i.MachineName == machineName
				&& i.HostName == hostName);
			if (existing != null)
			{
				existing.IsRunning = false;
			}
		}
	}
}
